/* 该程序在命令行指定的路径中创建了一个命名管道，然后分支出一个子进程。子进程向命名管道写入，
 * 父进程则读取子进程写入的内容。该程序中还包括下哦物检测，并用进程ID标识每条消息
 * 对消息进行标识非常重要，因为父进程和子进程共享标准错误
 */

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include "restart.h"

#define BUFSIZE 256
#define FIFO_PERM (S_IRUSR | S_IWUSR)

// dofifochild函数显示的是子进程向管道中写入时所采取的动作
int dofifochild(const char *fifoname, const char *idstring);
int dofifoparent(const char *fifoname);

int main (int argc, char *argv[]) {
    pid_t childpid;

    // 命令行有管道名
    if (argc != 2) {
        fprintf(stderr, "Usage: %s pipename\n", argv[0]);
        return -1;
    }

    // 创建一个命名管道
    int ret = mkfifo(argv[1], FIFO_PERM);
    if(ret == -1 && errno != EEXIST) {
        fprintf(stderr, "[%ld]: failed to create named pipe %s : %s\n",
                (long)getpid(), argv[1], strerror(errno));

        return -1;
    }

    childpid = fork();
    if(childpid == -1) {
        perror("Failed to fork");
        return -1;
    }

    if (childpid == 0) {
        return dofifochild(argv[1], "this was written by the child");
    } else {
        return dofifoparent(argv[1]);
    }
}


int dofifochild(const char *fifoname, const char *idstring){
    char buf[BUFSIZE];
    int fd;
    int rval;
    ssize_t strsize;

    fprintf(stderr, "[%ld] : (child) about to open FIFO %s ...\n",
            (long)getpid(), fifoname);

    fd = open(fifoname, O_WRONLY);
    while (fd == -1 && errno == EINTR);
    if (fd == -1) {
        fprintf(stderr, "[%ld] : failed to open named pipe %s for write: %s\n",
                (long)getpid(), fifoname, strerror(errno));
        return -1;
    }

    rval = snprintf(buf, BUFSIZE, "[%ld] : %s\n", (long)getpid(), idstring);
    if (rval < 0) {
        fprintf(stderr, "[%ld]: failed to make the string:\n", (long)getpid());
        return -1;
    }

    strsize = strlen(buf) + 1;
    fprintf(stderr, "[%ld] : about to write...\n", (long)getpid());
    rval = r_write(fd, buf, strsize);
    if (rval != strsize) {
        fprintf(stderr, "[%ld]: failed to write to pipe: %s\n", (long)getpid(), strerror(errno));
        return -1;
    }

    fprintf(stderr, "[%ld] : finising...\n", (long)getpid());

    return 0;
}


int dofifoparent(const char *fifoname) {
    char buf[BUFSIZE];
    int fd;
    int rval;

    fprintf(stderr, "[%ld] : (parent) about to open FIFO %s ...\n",
            (long)getpid(), fifoname);

    fd = open(fifoname, FIFO_PERM);
    while (fd == -1 && errno == EINTR);
    if (fd == -1) {
        fprintf(stderr, "[%ld] : failed to open named pipe %s for write: %s\n",
                (long)getpid(), fifoname, strerror(errno));
        return -1;
    }

    fprintf(stderr, "[%ld] : about to read...\n", (long)getpid());
    rval = r_read(fd, buf, BUFSIZE);
    if (rval == -1) {
        fprintf(stderr, "[%ld]: failed to read from pipe: %s\n", (long)getpid(), strerror(errno));
        return -1;
    }

    fprintf(stderr, "[%ld] : read %.*s\n", (long)getpid(), rval, buf);

    return 0;
}